package com.innovation.ic.b1b.monitor.base.handler;

import com.alibaba.druid.pool.DruidDataSource;
import com.google.common.base.Strings;
import com.innovation.ic.b1b.framework.manager.JdbcManager;
import com.innovation.ic.b1b.monitor.base.mapper.MySqlMapper;
import com.innovation.ic.b1b.monitor.base.mapper.MysqlAvailableJobLogMapper;
import com.innovation.ic.b1b.monitor.base.mapper.MysqlAvailableJobMapper;
import com.innovation.ic.b1b.monitor.base.model.Mysql;
import com.innovation.ic.b1b.monitor.base.model.MysqlAvailableJob;
import com.innovation.ic.b1b.monitor.base.model.MysqlAvailableJobLog;
import com.innovation.ic.b1b.monitor.base.pojo.constant.JobDataMapConstant;
import com.innovation.ic.b1b.monitor.base.pojo.constant.MysqlAvailableJobConstant;
import com.innovation.ic.b1b.monitor.base.pojo.enums.ActiveEnum;
import com.innovation.ic.b1b.monitor.base.value.TimeSetConfig;
import lombok.SneakyThrows;
import org.quartz.JobDataMap;
import org.quartz.JobExecutionException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.quartz.QuartzJobBean;
import javax.annotation.Resource;
import java.sql.*;
import java.util.Random;

/**
 * @desc   监控mysql可用任务处理类
 * @author linuo
 * @time   2023年3月23日14:08:54
 */
public class MysqlAvailableJobHandler extends QuartzJobBean {
    private Logger log = LoggerFactory.getLogger(this.getClass());

    @Resource
    private HandlerHelper handlerHelper;

    @Resource
    private MySqlMapper mysqlMapper;

    @Resource
    private TimeSetConfig timeSetConfig;

    @Resource
    private MysqlAvailableJobMapper mysqlAvailableJobMapper;

    @Resource
    private MysqlAvailableJobLogMapper mysqlAvailableJobLogMapper;

    @SneakyThrows
    @Override
    protected void executeInternal(org.quartz.JobExecutionContext jobExecutionContext) throws JobExecutionException {
        log.info("开始执行监控mysql可用任务");

        // 获取1-5间的随机数
        int min = 1;
        int max = 5;
        Random random = new Random();
        int s = random.nextInt(max) % (max - min + 1) + min;
        int sleepTime = s * 1000;
        log.info("休眠[{}]秒", s);
        Thread.sleep(sleepTime);

        JobDataMap jobDataMap = jobExecutionContext.getMergedJobDataMap();
        int id = jobDataMap.getInt(JobDataMapConstant.ID);
        MysqlAvailableJob mysqlAvailableJob = mysqlAvailableJobMapper.selectById(id);
        if(mysqlAvailableJob != null){
            Mysql mysql = mysqlMapper.selectById(mysqlAvailableJob.getMysqlId());
            if(mysql != null){
                String mysqlName = mysql.getName();

                // 存活状态
                Integer active = ActiveEnum.NO.getCode();

                // mysql可用任务日志表实体
                MysqlAvailableJobLog mysqlAvailableJobLog = new MysqlAvailableJobLog();
                mysqlAvailableJobLog.setMysqlAvailableJobId(id);
                mysqlAvailableJobLog.setStartTime(new Date(System.currentTimeMillis()));

                if(Strings.isNullOrEmpty(mysql.getUrl()) || Strings.isNullOrEmpty(mysql.getUserName()) || Strings.isNullOrEmpty(mysql.getPassword())){
                    String message = mysqlName + "配置信息不完整,无法检测是否存活";
                    log.info(message);
                    mysqlAvailableJobLog.setDescription(message);
                }else {
                    // 判断mysql是否可用
                    String message = judgeMysqlIfActive(mysql);
                    if (message == null) {
                        active = ActiveEnum.YES.getCode();
                    } else {
                        mysqlAvailableJobLog.setDescription(message);
                    }
                }

                mysqlAvailableJobLog.setActive(active);
                int insert = mysqlAvailableJobLogMapper.insert(mysqlAvailableJobLog);
                if(insert > 0){
                    log.info("mysql可用任务日志插入成功");

                    if(active.intValue() == ActiveEnum.NO.getCode().intValue()){
                        // 发送邮件
                        String message = mysqlName + "出现异常，原因：" + mysqlAvailableJobLog.getDescription() + "，请查看mysql状态并及时进行异常处理。";
                        handlerHelper.sendEmail(mysqlAvailableJob.getAlarmEmail(), message, null);
                    }
                }
            }else{
                log.info("未在mysql表中查询到id=[{}]的配置信息,无法执行监控mysql可用任务", mysqlAvailableJob.getMysqlId());
            }
        }else{
            log.info("监控mysql可用任务id为[{}]的数据不存在,无法执行任务", id);
        }
    }

    /**
     * 判断mysql是否可用
     * @param mysql mysql配置信息
     * @return 返回结果
     */
    private String judgeMysqlIfActive(Mysql mysql) throws InterruptedException {
        String message = null;
        try {
            log.info("第一次执行监控mysql是否可用任务");
            JdbcManager jdbcManager = new JdbcManager(MysqlAvailableJobConstant.MYSQL_CLASS_NAME, mysql.getUrl(), mysql.getUserName(), mysql.getPassword());
            DruidDataSource dataSource = jdbcManager.getDataSource();
            if(dataSource != null){
                log.info("连接:[{}]数据库成功", mysql.getUrl());
                dataSource.close();
                jdbcManager.close();
            }else{
                jdbcManager.close();
            }
        }catch (Exception e) {
            log.info("第一次连接:[{}]数据库失败,原因:[{}],待{}秒后重试连接", mysql.getUrl(), e.toString(), timeSetConfig.getRetryWaitTime());
            Thread.sleep(timeSetConfig.getRetryWaitTime() * 1000);

            try {
                log.info("第二次执行监控mongodb是否可用任务");
                JdbcManager jdbcManager = new JdbcManager(MysqlAvailableJobConstant.MYSQL_CLASS_NAME, mysql.getUrl(), mysql.getUserName(), mysql.getPassword());
                DruidDataSource dataSource = jdbcManager.getDataSource();
                if(dataSource != null){
                    log.info("连接:[{}]数据库成功", mysql.getUrl());
                    dataSource.close();
                    jdbcManager.close();
                }else{
                    jdbcManager.close();
                }
            } catch (Exception e1) {
                log.info("第二次连接:[{}]数据库失败,原因:[{}],待{}秒后重试连接", mysql.getUrl(), e1.toString(), timeSetConfig.getRetryWaitTime());
                Thread.sleep(timeSetConfig.getRetryWaitTime() * 1000);

                try {
                    log.info("第三次执行监控mongodb是否可用任务");
                    JdbcManager jdbcManager = new JdbcManager(MysqlAvailableJobConstant.MYSQL_CLASS_NAME, mysql.getUrl(), mysql.getUserName(), mysql.getPassword());
                    DruidDataSource dataSource = jdbcManager.getDataSource();
                    if(dataSource != null){
                        log.info("连接:[{}]数据库成功", mysql.getUrl());
                        dataSource.close();
                        jdbcManager.close();
                    }else{
                        jdbcManager.close();
                    }
                } catch (Exception e2) {
                    message = e2.toString();
                    log.info("第三次连接:[{}]数据库失败,原因:[{}],认定为当前数据库连接失败,记录错误原因", mysql.getUrl(), e2.toString());
                }
            }
        }

        if (!Strings.isNullOrEmpty(message)) {
            if (message.length() > 100) {
                message = message.substring(0, 100);
            }
        }

        return message;
    }
}